package com.amigo.online.provider.video.service.impl;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.amigo.online.common.base.security.LocalUser;
import com.amigo.online.common.core.response.Response;
import com.amigo.online.common.param.dto.adv.AdvRecommendDto;
import com.amigo.online.common.param.dto.video.RecommendVideoDto;
import com.amigo.online.common.param.result.LocalUserInfo;
import com.amigo.online.common.param.result.MusicInfo;
import com.amigo.online.common.param.result.VideoAdvInfo;
import com.amigo.online.common.param.result.VideoInfo;
import com.amigo.online.common.param.result.VideoInfo.VideoUserInfo;
import com.amigo.online.provider.video.common.GlobalController;
import com.amigo.online.provider.video.common.RwRedisService;
import com.amigo.online.provider.video.mapper.PromoteMapper;
import com.amigo.online.provider.video.mapper.VideoMapper;
import com.amigo.online.provider.video.mapper.VideoRecommendMapper;
import com.amigo.online.provider.video.mapper.VideoUpMapper;
import com.amigo.online.provider.video.model.entity.PromoteVideo;
import com.amigo.online.provider.video.service.AdvFeignService;
import com.amigo.online.provider.video.service.RecommendVideoService;
import com.amigo.online.provider.video.service.UserFeignService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

@Service
public class RecommendVideoServiceImpl implements RecommendVideoService {

    @Autowired
    VideoMapper videoMapper;

    @Autowired
    VideoRecommendMapper videoRecommendMapper;

    @Autowired
    RwRedisService rwRedisService;

    @Autowired
    AdvFeignService advFeignService;

    @Autowired
    PromoteMapper promoteMapper;

    @Autowired
    UserFeignService userFeignService;

    @Autowired
    private VideoUpMapper videoUpMapper;

    private final static int VIDEO_COUNT_ONE_PAGE = 10;
    private final static String LOOKED_VIDEO_ID_KEY_PREFIX = "v:mvi:";
    private final static String LOOKED_PROMOTE_VIDEO_ID_KEY_PREFIX = "v:mpvi:";

    @Override
    public List<VideoInfo> recomendedVideoList(RecommendVideoDto dto) {
        LocalUserInfo info = LocalUser.getUser();
        String lookedVideoIdKey = LOOKED_VIDEO_ID_KEY_PREFIX + dto.getDeviceId();
        if (info != null) { // 已经登录，用userid记录
            lookedVideoIdKey = LOOKED_VIDEO_ID_KEY_PREFIX + info.getUser().getId();
        }
        // 已观看的视频
        @SuppressWarnings({"unchecked", "rawtypes"})
        Set<Integer> allSet = (Set) rwRedisService.opsForZSetRead().reverseRange(lookedVideoIdKey, 0, -1);
        int start = (VIDEO_COUNT_ONE_PAGE - 4) * (dto.getPage() - 1);
        System.out.println("观看历史是:" + allSet);
        // 获取6 个推荐视频
        List<VideoInfo> videoInfoList = videoRecommendMapper.getRecomendedVideoNotInIds(start, VIDEO_COUNT_ONE_PAGE - 4,
                allSet.stream().map(e -> e.longValue()).collect(Collectors.toList()));

        if (videoInfoList.size() < VIDEO_COUNT_ONE_PAGE - 4) {
            // 清除redis中视频观看记录
            rwRedisService.delete(lookedVideoIdKey);
            videoInfoList = videoRecommendMapper.getRecomendedVideoNotInIds(start, VIDEO_COUNT_ONE_PAGE - 4, null);
        }

        // 把2个模特视频随机插入到videoInfoList中
        randomAddVideo(videoInfoList, videoRecommendMapper.getModleVideoNotInIds(2,
                allSet.stream().map(e -> e.longValue()).collect(Collectors.toList())));

        // 把2个速推视频随机插入到videoInfoList中
        randomAddVideo(videoInfoList, getPromoteVideo(dto));

        // 把2个广告视频随机插入到videoInfoList中
        randomAddVideo(videoInfoList, getAdvVideo(dto));


        // 用户登录的情况下判断该用户是否点赞了该视频、是否关注了此视频的发布者
        if (info != null) {
            List<Long> userIds = new ArrayList<>();
            List<Long> videoIds = new ArrayList<>();
            HashMap<Long, VideoInfo> videoMap = new HashMap<>(32);
            HashMap<Long, VideoInfo> videoUserMap = new HashMap<>(32);
            for (VideoInfo videoInfo : videoInfoList) {
                userIds.add(videoInfo.getUserId());
                videoIds.add(videoInfo.getId());
                videoMap.put(videoInfo.getId(), videoInfo);
                videoUserMap.put(videoInfo.getUserId(), videoInfo);
            }
            // 根据用户id查出该用户所关注的人
            Object om = userFeignService.findFollowStateByUserIdAndUserIds(info.getUser().getId(), userIds).getBody()
                    .getData();
            ObjectMapper x = new ObjectMapper();
            List<Long> followedIds = x.convertValue(om, new TypeReference<List<Long>>() {
            });
            if (!videoIds.isEmpty()) {
                List<Long> upIds = videoUpMapper
                        .findUserUpStateByUserIdAndVideoIds(GlobalController.getNowUser().getId(), videoIds);
                if (upIds != null) {
                    for (Long videoId : upIds) {
                        videoMap.get(videoId).getUser().setUped(true);
                    }
                }
            }
            if (followedIds != null) {
                for (Long userId : followedIds) {
                    videoUserMap.get(userId).getUser().setFollowed(true);
                }
            }
        }

        for (VideoInfo videoInfo : videoInfoList) {
            System.out.println("videoId:" + videoInfo.getId() + " ; promoteId:" + videoInfo.getPromote_id() + " ; ads:" + videoInfo.getAds());
        }
        return videoInfoList;
    }

    private List<VideoInfo> getAdvVideo(RecommendVideoDto dto) {
        AdvRecommendDto advRecommendDto = new AdvRecommendDto(null, null, dto.getSex(), null, null, null);
        advRecommendDto.setNumber(2);
        ResponseEntity<Response> res = advFeignService.getRecommendVideoInfo(advRecommendDto);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        List<VideoAdvInfo> advlist = objectMapper.convertValue(res.getBody().getData(),
                new TypeReference<List<VideoAdvInfo>>() {
                });
        if (advlist == null) {
            advlist = new ArrayList<>();
        }
        List<VideoInfo> videoInfoList = new ArrayList<>();
        for (VideoAdvInfo videoAdvInfo : advlist) {
            videoAdvInfo.setAds(1);// 广告视频
            VideoUserInfo user = new VideoUserInfo();
            user.setAvatar(videoAdvInfo.getAdvUserAvatarUrl());
            user.setNickname(videoAdvInfo.getAdvUserName());
            videoAdvInfo.setUser(user);
            MusicInfo music = new MusicInfo();
            music.setMusic(videoAdvInfo.getAdvMusicUrl());
            music.setName(videoAdvInfo.getAdvMusicName());
            videoAdvInfo.setMusic(music);
            videoInfoList.add(videoAdvInfo);
        }

        return videoInfoList;
    }

    private void randomAddVideo(List<VideoInfo> videoInfoList, List<VideoInfo> promoteVideoList) {
        for (VideoInfo videoInfo : promoteVideoList) {
            videoInfoList.add(new Random().nextInt(videoInfoList.size() + 1), videoInfo);
        }

    }

    private List<VideoInfo> getPromoteVideo(RecommendVideoDto dto) {
        LocalUserInfo info = LocalUser.getUser();
        // 已经登录，用userid记录
        String lookedPromoteVideoIdKey = LOOKED_PROMOTE_VIDEO_ID_KEY_PREFIX
                + (info == null ? dto.getDeviceId() : String.valueOf(info.getUser().getId()));

        @SuppressWarnings("unchecked")
        Set<Long> lookedVideoIds = (Set) rwRedisService.opsForSetRead().members(lookedPromoteVideoIdKey);

        List<PromoteVideo> promoteVideoList = new ArrayList<>();
        // 搜索条件
        Long area_ids = null;
        Long age = null;
        String sex = null;
        if (info != null) {// 已登录
            LocalDateTime birthday = LocalDateTime.ofInstant(Instant.ofEpochMilli(info.getUser().getBirthday()),
                    ZoneId.systemDefault());
            age = ChronoUnit.YEARS.between(birthday, LocalDateTime.now());
            sex = info.getUser().getSex();
        }

        promoteVideoList = getPromoteVideo(new ArrayList<>(lookedVideoIds), sex, age, area_ids);
        // 如果速推视频不足2个，则扩大搜索条件(清空条件)
        if (promoteVideoList.size() < 2) {
            area_ids = null;
            age = null;
            sex = null;
            promoteVideoList = getPromoteVideo(new ArrayList<>(lookedVideoIds), sex, age, area_ids);
        }
//		// 最大搜索条件视频还不足
//		if (promoteVideoList.size() < 2) {
//			promoteVideoList = getPromoteVideo(null, sex, age, area_ids);
//			// 清除速推视频观看缓存
//			rwRedisService.delete(lookedPromoteVideoIdKey);
//		}

        List<VideoInfo> rs = promoteVideoList.isEmpty() ? new ArrayList<>()
                : videoRecommendMapper.getRecomendedVideoInIds(
                promoteVideoList.stream().map(e -> e.getVideo_id()).collect(Collectors.toList()));
        //把速推id加到videoInfo中 ,循环次数 2X2
        for (VideoInfo videoInfo : rs) {
            for (PromoteVideo promoteVideo : promoteVideoList) {
                //不是速推视频的速推Id设置成0
                if (videoInfo.getId().equals(promoteVideo.getVideo_id())) {
                    videoInfo.setPromote_id(promoteVideo.getId());
                    break;
                } else {
                    videoInfo.setPromote_id(0L);
                }
            }
        }

        //还是没有的话添加新用户视频
        if (promoteVideoList.size() < 2) {
            rs = getNewVideo(dto.getDeviceId(), dto.getPage(),2-promoteVideoList.size());
        }
        return rs;
    }

    private List<PromoteVideo> getPromoteVideo(List<Long> lookedVideoIds, String sex, Long age, Long area_ids) {
        List<PromoteVideo> promoteVideo = promoteMapper.getPromoteVideo(lookedVideoIds, area_ids, sex);
        if (age != null) {
            String age_range = age > 18 && age < 23 ? "1" : age > 24 && age < 40 ? "2" : "3";
            for (PromoteVideo pv : promoteVideo) {
                if (pv.getAge_range().contains(age_range)) {
                    break;
                }
                promoteVideo.remove(pv);
            }
        }
        return promoteVideo;
    }

    private List<VideoInfo> getNewVideo(String dev,Integer page, Integer num) {
        int start = (VIDEO_COUNT_ONE_PAGE - 8) * (page - 1);
        LocalUserInfo info = LocalUser.getUser();
        String lookedVideoIdKey = LOOKED_VIDEO_ID_KEY_PREFIX + dev;
        if (info != null) { // 已经登录，用userid记录
            lookedVideoIdKey = LOOKED_VIDEO_ID_KEY_PREFIX + info.getUser().getId();
        }
        Set<Integer> allSet = (Set) rwRedisService.opsForZSetRead().reverseRange(lookedVideoIdKey, 0, -1);
        List<VideoInfo> newVideo = videoRecommendMapper.getNewVideo(allSet.stream().map(e -> e.longValue()).collect(Collectors.toList()),start, num);
        System.out.println("newVideoGet");
        return newVideo;
    }

}
